home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / bbs / tdk_v136.zip / ASYNC.PAS < prev    next >
Pascal/Delphi Source File  |  1997-07-01  |  60KB  |  1,178 lines

  1. {
  2.  ▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀    ▀▀   ▀▀
  3.    ▀▀     ▀▀   ▀▀   ▀▀  ▀▀
  4.   ▀▀     ▀▀   ▀▀▀  ▀▀▀▀▀  The DoorKit!
  5.  ▀▀     ▀▀   ▀▀   ▀▀  ▀▀
  6. ▀▀     ▀▀▀▀▀▀    ▀▀    ▀▀
  7. The BBS Door Development Kit By The People - For The People!
  8.  
  9.  
  10.    Feel free to modify or optimize this code at will. All I ask is that if
  11.    find a better way to do things (and you will), please send me a copy of
  12.    your modifications. Thanks in advance!....Larry L. Athey....}
  13.  
  14. {*--------------------------------------------------------------------------*}
  15. {*                                                                          *}
  16. {*  Status byte definition (C_Status):                                      *}
  17. {*                                                                          *}
  18. {*  7   6   5   4   3   2   1   0                                           *}
  19. {*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
  20. {*  |   |   |   |   |   |   |________ Input buffer full                     *}
  21. {*  |   |   |   |   |   |____________ Output buffer empty                   *}
  22. {*  |   |   |   |   |________________ Output buffer full                    *}
  23. {*  |   |   |   |____________________ Input buffer overflow                 *}
  24. {*  |   |   |________________________ Output buffer overflow                *}
  25. {*  |   |____________________________ Hard handshake active (xmit stopped)  *}
  26. {*  |________________________________ Soft handshake active (xmit stopped)  *}
  27. {*                                                                          *}
  28. {*  Control byte definition (C_Ctrl):                                       *}
  29. {*                                                                          *}
  30. {*  7   6   5   4   3   2   1   0                                           *}
  31. {*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
  32. {*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
  33. {*  |   |   |   |   |   |____________ Enable software handshake             *}
  34. {*  |   |   |   |   |________________                                       *}
  35. {*  |   |   |   |____________________                                       *}
  36. {*  |   |   |________________________                                       *}
  37. {*  |   |____________________________                                       *}
  38. {*  |________________________________                                       *}
  39. {*                                                                          *}
  40. {****************************************************************************}
  41.  
  42. {$A+,B-,D+,E+,F+,G+,I-,L+,N-,O+,P-,Q-,R-,S-,T-,V+,X+}
  43. UNIT ASYNC;
  44.  
  45. INTERFACE
  46.  
  47. {----------------------------------------------------------------------------}
  48.  
  49. CONST
  50.   C_MinBaud  = 300;
  51.   C_MaxBaud  = 115200;
  52.   C_MaxPort  = 4;
  53.   C_MaxCom   : BYTE = C_MaxPort;
  54.   D_PortAddr : ARRAY[1..C_MaxPort] OF WORD = ($03F8,$02F8,$03E8,$02E8);
  55.   D_PortInt  : ARRAY[1..C_MaxPort] OF BYTE = (4,3,4,3);
  56.  
  57. {----------------------------------------------------------------------------}
  58.  
  59. TYPE
  60.   C_VectorArray  = ARRAY[0..15] OF POINTER;
  61.   C_PointerArray = ARRAY[1..C_MaxPort]  OF POINTER;
  62.   C_WordArray    = ARRAY[1..C_MaxPort] OF WORD;
  63.   C_ByteArray    = ARRAY[1..C_MaxPort] OF BYTE;
  64.   C_CharArray    = ARRAY[1..C_MaxPort] OF CHAR;
  65.   C_BooleanArray = ARRAY[1..C_MaxPort] OF BOOLEAN;
  66.  
  67. {----------------------------------------------------------------------------}
  68.  
  69. VAR
  70.   { Base port addresses & interrupt usage }
  71.   C_PortAddr : ARRAY[1..C_MaxPort] OF WORD;
  72.   C_PortInt  : ARRAY[1..C_MaxPort] OF BYTE;
  73.   ComPort  : BYTE;
  74.   C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  75.   C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  76.   C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  77.   C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  78.   C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  79.   C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  80.   C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  81.   C_XL3Ptr               : C_ByteArray;
  82.   C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  83.   C_Temp                 : WORD;              { Used for debugging }
  84.   C_msrport              : WORD;
  85. { RTSOn,RTSOff           : Word;}             { RTS assert/drop buffer points }
  86.   oldier,oldmcr          : BYTE;
  87.   c_buffull              : c_wordarray;
  88.   C_Cascade              : BYTE;              { Flag set 0 normally }
  89.   C_CascadeOK            : BOOLEAN;           { Flag if IRQ > 7 }
  90.  
  91. {----------------------------------------------------------------------------}
  92.  
  93. FUNCTION  ComReadCh(ComPort : BYTE) : CHAR;
  94. FUNCTION  ComReadChW(ComPort : BYTE) : CHAR;
  95. {Procedure ComWriteCh(ComPort:Byte; Ch:Char); }
  96. PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR);
  97. PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
  98. PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
  99. {Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  100. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);}
  101. FUNCTION  CTSStat(ComPort : BYTE) : BOOLEAN;
  102. FUNCTION  RTSStat(ComPort : BYTE) : BOOLEAN;
  103. FUNCTION  DSRStat(ComPort : BYTE) : BOOLEAN;
  104. FUNCTION  RIStat(ComPort : BYTE) : BOOLEAN;
  105. FUNCTION  DCDStat(ComPort : BYTE) : BOOLEAN;
  106. PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
  107. PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
  108. PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
  109. PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
  110. FUNCTION  ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
  111. PROCEDURE ComWaitForClear(ComPort : BYTE);
  112. PROCEDURE ComWrite(ComPort : BYTE; St : STRING);
  113. PROCEDURE ComWriteln(ComPort : BYTE; St : STRING);
  114. PROCEDURE ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
  115. PROCEDURE ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
  116. FUNCTION  ComExist(ComPort : BYTE) : BOOLEAN;
  117. FUNCTION  ComTrueBaud(Baud : LONGINT) : REAL;
  118. PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
  119. FUNCTION  OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
  120. PROCEDURE CloseCom(ComPort : BYTE);
  121. PROCEDURE CloseAllComs;
  122.  
  123. {----------------------------------------------------------------------------}
  124.  
  125. IMPLEMENTATION
  126.  
  127. Uses DOS,CRT;
  128.  
  129. {$L ASYNC.OBJ}
  130.  
  131. CONST
  132.   C_IER = 1;                           { 8250 register offsets }
  133.   C_IIR = 2;
  134.   C_LCR = 3;
  135.   C_MCR = 4;
  136.   C_LSR = 5;
  137.   C_MSR = 6;
  138.   C_SCR = 7;
  139.  
  140. VAR
  141.   C_OldINTVec : C_VectorArray;        { Storage for old hardware INT vectors }
  142.   X : BYTE;                            { Used by initialization code }
  143.  
  144. {****************************************************************************}
  145. {*                                                                          *}
  146. {*  Procedure INT_Handler; External;                                        *}
  147. {*                                                                          *}
  148. {*  Hardware interrupts 0-15 (vectors $08 - $0F,$70 - $77) are pointed to   *}
  149. {*  this routine.  It is for internal use only and should NOT be called     *}
  150. {*  directly.  Written in assembly language (see SLASYNC.ASM).              *}
  151. {*                                                                          *}
  152. {****************************************************************************}
  153.  
  154. PROCEDURE INT_Handler; EXTERNAL;
  155.  
  156. {****************************************************************************}
  157. {*                                                                          *}
  158. {*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
  159. {*                                                                          *}
  160. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  161. {*                                                                          *}
  162. {*  Returns character from input buffer of specified port.  If the buffer   *}
  163. {*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
  164. {*  Written in assembly language for best possible speed (see ASYNC11.ASM)  *}
  165. {*                                                                          *}
  166. {****************************************************************************}
  167.  
  168. FUNCTION ComReadCh(ComPort : BYTE) : CHAR; EXTERNAL;
  169.  
  170. {****************************************************************************}
  171. {*                                                                          *}
  172. {*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
  173. {*                                                                          *}
  174. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  175. {*                                                                          *}
  176. {*  Works like ComReadCh, but will wait until at least 1 character is       *}
  177. {*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
  178. {*  works much like the ReadKey predefined function.  Written in assembly   *}
  179. {*  language to maximize performance (see ASYNC11.ASM)                      *}
  180. {*                                                                          *}
  181. {****************************************************************************}
  182.  
  183. FUNCTION ComReadChW(ComPort : BYTE) : CHAR; EXTERNAL;
  184.  
  185. {****************************************************************************}
  186. {*                                                                          *}
  187. {*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
  188. {*                                                                          *}
  189. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  190. {*  Ch:Char       ->  Character to send                                     *}
  191. {*                                                                          *}
  192. {*  Places the character [Ch] in the transmit buffer of the specified port. *}
  193. {*  If the port specified is not open or nonexistent, or if the buffer is   *}
  194. {*  filled, the character is discarded.  Written in assembly language to    *}
  195. {*  maximize performance (see ASYNC11.ASM)                                  *}
  196. {*                                                                          *}
  197. {****************************************************************************}
  198.  
  199. PROCEDURE ComWriteCh(ComPort : BYTE; Ch : CHAR); EXTERNAL;
  200.  
  201. {****************************************************************************}
  202. {*                                                                          *}
  203. {*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
  204. {*                                                                          *}
  205. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  206. {*  Ch:Char       ->  Character to send                                     *}
  207. {*                                                                          *}
  208. {*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
  209. {*  available in the output buffer before attempting to place the character *}
  210. {*  [Ch] in it.  Allows the programmer to send characters without regard to *}
  211. {*  available buffer space.  Written in assembly language to maximize       *}
  212. {*  performance (see ASYNC11.ASM)                                           *}
  213. {*                                                                          *}
  214. {****************************************************************************}
  215.  
  216. PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR); EXTERNAL;
  217.  
  218. {****************************************************************************}
  219. {*                                                                          *}
  220. {*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
  221. {*                                                                          *}
  222. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  223. {*                      Call ignored if out-of-range                        *}
  224. {*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
  225. {*                                                                          *}
  226. {*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
  227. {*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
  228. {*  state, signalling to a remote system that the host is "on-line"         *}
  229. {*  (although not nessesarily ready to receive data - see SetRTS).          *}
  230. {*                                                                          *}
  231. {****************************************************************************}
  232.  
  233. PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
  234. VAR
  235.   P,X : INTEGER;
  236. BEGIN
  237.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
  238.   P := C_PortAddr[ComPort];
  239.   X := Port[P + C_MCR];
  240.   IF Assert THEN
  241.     X := X OR $01
  242.   ELSE
  243.     X := X AND $FE;
  244.   Port[P + C_MCR] := X;
  245. END;
  246.  
  247. {****************************************************************************}
  248. {*                                                                          *}
  249. {*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
  250. {*                                                                          *}
  251. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  252. {*                      Call ignored if out-of-range                        *}
  253. {*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
  254. {*                                                                          *}
  255. {*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
  256. {*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
  257. {*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
  258. {*  should NOT be used if RTS handshaking is enabled.                       *}
  259. {*                                                                          *}
  260. {****************************************************************************}
  261.  
  262. PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
  263. VAR
  264.   P,X : INTEGER;
  265. BEGIN
  266.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
  267.   P := C_PortAddr[ComPort];
  268.   X := Port[P + C_MCR];
  269.   IF Assert THEN
  270.     X := X OR $02
  271.   ELSE
  272.     X := X AND $FD;
  273.   Port[P + C_MCR] := X;
  274. END;
  275.  
  276. {****************************************************************************}
  277. {*                                                                          *}
  278. {*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
  279. {*                                                                          *}
  280. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  281. {*                      Call ignored if out-of-range                        *}
  282. {*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
  283. {*                                                                          *}
  284. {*  SetOUT1 is provided for reasons of completeness only, since the         *}
  285. {*  standard PC/XT/AT configurations do not utilize this control signal.    *}
  286. {*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
  287. {*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
  288. {*  of the 8250 (but not on the port itself).                               *}
  289. {*                                                                          *}
  290. {****************************************************************************}
  291. {
  292. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  293. Var
  294.   P,X : Integer;
  295. Begin
  296.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  297.   P := C_PortAddr[ComPort];
  298.   X := Port[P+C_MCR];
  299.   If Assert Then
  300.     X := X Or $04
  301.   Else
  302.     X := X And $FB;
  303.   Port[P+C_MCR] := X;
  304. End;
  305.  }
  306. {****************************************************************************}
  307. {*                                                                          *}
  308. {*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
  309. {*                                                                          *}
  310. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  311. {*                      Call ignored if out-of-range                        *}
  312. {*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
  313. {*                                                                          *}
  314. {*  The OUT2 signal line, although not available on the port itself, is     *}
  315. {*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
  316. {*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
  317. {*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
  318. {*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
  319. {*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
  320. {*                                                                          *}
  321. {****************************************************************************}
  322. {
  323. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  324. Var
  325.   P,X : Integer;
  326. Begin
  327.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  328.   P := C_PortAddr[ComPort];
  329.   X := Port[P+C_MCR];
  330.   If Assert Then
  331.     X := X Or $08
  332.   Else
  333.     X := X And $F7;
  334.   Port[P+C_MCR] := X;
  335. End;
  336.  }
  337. {****************************************************************************}
  338. {*                                                                          *}
  339. {*  Function CTSStat(ComPort:Byte) : Boolean                                *}
  340. {*                                                                          *}
  341. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  342. {*                    Call ignored if out-of-range                          *}
  343. {*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
  344. {*                                                                          *}
  345. {*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
  346. {*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
  347. {*  signals the host (this computer) that the receiver is ready to accept   *}
  348. {*  data (in contrast to the DSR line, which signals the receiver as        *}
  349. {*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
  350. {*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
  351. {*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
  352. {*  terrogate this line manually.                                           *}
  353. {*                                                                          *}
  354. {****************************************************************************}
  355.  
  356. FUNCTION CTSStat(ComPort : BYTE) : BOOLEAN;
  357. BEGIN
  358.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  359.     CTSStat := FALSE
  360.   ELSE
  361.     CTSStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $10 <> $10);
  362. END;
  363.  
  364. {****************************************************************************}
  365. {*                                                                          *}
  366. {*  Function RTSStat(ComPort:Byte) : Boolean                                *}
  367. {*                                                                          *}
  368. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  369. {*                    Call ignored if out-of-range                          *}
  370. {*  Returns status of Ready-To-Send line (TRUE if RTS asserted)             *}
  371. {*                                                                          *}
  372. {****************************************************************************}
  373.  
  374. FUNCTION RTSStat(ComPort : BYTE) : BOOLEAN;
  375. BEGIN
  376.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  377.     RTSStat := FALSE
  378.   ELSE
  379.     RTSStat := (Port[C_PortAddr[ComPort] + C_LSR] AND $20 <> $20);
  380. END;
  381.  
  382. {****************************************************************************}
  383. {*                                                                          *}
  384. {*  Function DSRStat(ComPort:Byte) : Boolean                                *}
  385. {*                                                                          *}
  386. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  387. {*                    Call ignored if out-of-range                          *}
  388. {*  Returns status of Data Set Ready (DSR) signal line.                     *}
  389. {*                                                                          *}
  390. {*  The Data Set Ready (DSR) line is typically used by a remote station     *}
  391. {*  to signal the host system that it is on-line (although not nessesarily  *}
  392. {*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
  393. {*  line asserted if DSRStat returns TRUE.                                  *}
  394. {*                                                                          *}
  395. {****************************************************************************}
  396.  
  397. FUNCTION DSRStat(ComPort : BYTE) : BOOLEAN;
  398. BEGIN
  399.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  400.     DSRStat := FALSE
  401.   ELSE
  402.     DSRStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $20) > 0;
  403. END;
  404.  
  405. {****************************************************************************}
  406. {*                                                                          *}
  407. {*  Function RIStat(ComPort:Byte) : Boolean                                 *}
  408. {*                                                                          *}
  409. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  410. {*                    Call ignored if out-of-range                          *}
  411. {*                                                                          *}
  412. {*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
  413. {*  typically used only by modems, and indicates that the modem has detect- *}
  414. {*  ed an incoming call if RIStat returns TRUE.                             *}
  415. {*                                                                          *}
  416. {****************************************************************************}
  417.  
  418. FUNCTION RIStat(ComPort : BYTE) : BOOLEAN;
  419. BEGIN
  420.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  421.     RIStat := FALSE
  422.   ELSE
  423.     RIStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $40) > 0;
  424. END;
  425.  
  426. {****************************************************************************}
  427. {*                                                                          *}
  428. {*  Function DCDStat(ComPort:Byte) : Boolean                                *}
  429. {*                                                                          *}
  430. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  431. {*                    Call ignored if out-of-range                          *}
  432. {*                                                                          *}
  433. {*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
  434. {*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
  435. {*  the modem indicates that it has successfuly linked with another modem   *}
  436. {*  device at another site.                                                 *}
  437. {*                                                                          *}
  438. {****************************************************************************}
  439.  
  440. FUNCTION DCDStat(ComPort : BYTE) : BOOLEAN;
  441. BEGIN
  442.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  443.     DCDStat := FALSE
  444.   ELSE
  445.     DCDStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $80) > 0;
  446. END;
  447.  
  448. {****************************************************************************}
  449. {*                                                                          *}
  450. {*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
  451. {*                                                                          *}
  452. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  453. {*                    Request ignored if out of range or unopened.          *}
  454. {*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
  455. {*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
  456. {*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
  457. {*                                                                          *}
  458. {*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
  459. {*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
  460. {*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
  461. {*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
  462. {*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
  463. {*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
  464. {*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
  465. {*  The actual handshaking control is located in the interrupt driver for   *}
  466. {*  the port (see ASYNC11.ASM).                                             *}
  467. {*                                                                          *}
  468. {****************************************************************************}
  469.  
  470. PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
  471. VAR
  472.   X : BYTE;
  473. BEGIN
  474.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  475.   X := C_Ctrl[ComPort];
  476.   IF Mode THEN X := X OR $01 ELSE X := X AND $FE;
  477.   C_Ctrl[ComPort] := X;
  478.   IF Mode THEN
  479.     BEGIN
  480.       IF (RTSOff >= C_InSize[ComPort]) THEN RTSOff := C_InSize[ComPort] - 1;
  481.       IF (RTSOn > RTSOff) THEN RTSOff := RTSOn;
  482.       C_RTSOn[ComPort] := RTSOn;
  483.       C_RTSOff[ComPort] := RTSOff;
  484.     END;
  485. END;
  486.  
  487. {****************************************************************************}
  488. {*                                                                          *}
  489. {*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
  490. {*                                                                          *}
  491. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  492. {*                    Request ignored if out of range or unopened.          *}
  493. {*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
  494. {*                                                                          *}
  495. {*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
  496. {*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
  497. {*  if the remote drops the CTS line, the transmitter will be disabled      *}
  498. {*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
  499. {*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
  500. {*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
  501. {*  in any combination.  The actual logic for CTS handshaking is located    *}
  502. {*  in the communications interrupt driver (see ASYNC11.ASM).               *}
  503. {*                                                                          *}
  504. {****************************************************************************}
  505.  
  506. PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
  507. VAR
  508.   X : BYTE;
  509. BEGIN
  510.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  511.   X := C_Ctrl[ComPort];
  512.   IF Mode THEN X := X OR $02 ELSE X := X AND $FD;
  513.   C_Ctrl[ComPort] := X;
  514. END;
  515.  
  516. {****************************************************************************}
  517. {*                                                                          *}
  518. {*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
  519. {*                                                                          *}
  520. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  521. {*                    Request ignored if out of range or unopened.          *}
  522. {*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
  523. {*  Start:Char    ->  START control character (usually ^Q)                  *}
  524. {*                    Defaults to ^Q if character passed is >= <Space>      *}
  525. {*  Stop:Char     ->  STOP control character (usually ^S)                   *}
  526. {*                    Defaults to ^S if character passed is >= <Space>      *}
  527. {*                                                                          *}
  528. {*  SoftHandshake controls the usage of "Software" (control-character)      *}
  529. {*  handshaking on transmission.  If "software handshake" is enabled        *}
  530. {*  ([Mode] is TRUE), transmission will be halted if the character in       *}
  531. {*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
  532. {*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
  533. {*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
  534. {*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
  535. {*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
  536. {*  for <Stop>) will be used.  Software handshaking control is implimented  *}
  537. {*  within the communications interrupt driver (see ASYNC11.ASM).           *}
  538. {*                                                                          *}
  539. {****************************************************************************}
  540.  
  541. PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
  542. VAR
  543.   X : BYTE;
  544. BEGIN
  545.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  546.   X := C_Ctrl[ComPort];
  547.   IF Mode THEN
  548.     BEGIN
  549.       X := X OR $04;
  550.       IF Start = Stop THEN BEGIN Start := ^Q; Stop := ^S; END;
  551.       IF Start > #32 THEN Start := ^Q;
  552.       IF Stop > #32 THEN Stop := ^S;
  553.       C_StartChar[ComPort] := Start;
  554.       C_StopChar[ComPort] := Stop;
  555.     END
  556.   ELSE X := X AND $FB;
  557.   C_Ctrl[ComPort] := X;
  558. END;
  559.  
  560. {****************************************************************************}
  561. {*                                                                          *}
  562. {*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
  563. {*                                                                          *}
  564. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  565. {*                    Request ignored if out of range or unopened.          *}
  566. {*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
  567. {*                    No action taken if action code unrecognized.          *}
  568. {*                                                                          *}
  569. {*  ClearCom allows the user to completely clear the contents of either     *}
  570. {*  the input (receive) and/or output (transmit) buffers.  The "action      *}
  571. {*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
  572. {*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
  573. {*  if you wish to cancel a transmitted message or ignore part of a         *}
  574. {*  received message.                                                       *}
  575. {*                                                                          *}
  576. {****************************************************************************}
  577.  
  578. PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
  579. VAR
  580.   P,X : WORD;
  581. BEGIN
  582.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  583.   IO := UPCASE(IO);
  584.   P := C_PortAddr[ComPort];
  585.   INLINE($FA);
  586.   IF (IO = 'I') OR (IO = 'B') THEN
  587.     BEGIN
  588.       C_InHead[ComPort] := 0;
  589.       C_InTail[ComPort] := 0;
  590.       C_Status[ComPort] := (C_Status[ComPort] AND $EC) OR $01;
  591.       X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  592.     END;
  593.   IF (IO = 'O') OR (IO = 'B') THEN
  594.     BEGIN
  595.       C_OutHead[ComPort] := 0;
  596.       C_OutTail[ComPort] := 0;
  597.       C_Status[ComPort] := (C_Status[ComPort] AND $D3) OR $04;
  598.       X := Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  599.     END;
  600.   INLINE($FB);
  601. END;
  602.  
  603. {****************************************************************************}
  604. {*                                                                          *}
  605. {*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
  606. {*                                                                          *}
  607. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  608. {*                    Returns 0 if Port # invalid or unopened.              *}
  609. {*  IO:Char       ->  Action code; I=Input, O=Output                        *}
  610. {*                    Returns 0 if action code unrecognized.                *}
  611. {*                                                                          *}
  612. {*  ComBufferLeft will return a number (bytes) indicating how much space    *}
  613. {*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
  614. {*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
  615. {*  "action code" will return a result of 0.  Use this function when it is  *}
  616. {*  important to avoid program delays due to calls to output procedures or  *}
  617. {*  to prioritize the reception of data (to prevent overflows).             *}
  618. {*                                                                          *}
  619. {****************************************************************************}
  620.  
  621. FUNCTION ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
  622. BEGIN
  623.   ComBufferLeft := 0;
  624.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  625.   IO := UPCASE(IO);
  626.   IF IO = 'I' THEN
  627.     IF C_InHead[ComPort] >= C_InTail[ComPort] THEN
  628.       ComBufferLeft := C_InSize[ComPort] - (C_InHead[ComPort] - C_InTail[ComPort])
  629.     ELSE
  630.       ComBufferLeft := C_InTail[ComPort] - C_InHead[ComPort];
  631.   IF IO = 'O' THEN
  632.     IF C_OutHead[ComPort] >= C_OutTail[ComPort] THEN
  633.       ComBufferLeft := C_OutHead[ComPort] - C_OutTail[ComPort]
  634.     ELSE
  635.       ComBufferLeft := C_OutSize[ComPort] - (C_OutTail[ComPort] - C_OutHead[ComPort]);
  636. END;
  637.  
  638. {****************************************************************************}
  639. {*                                                                          *}
  640. {*  Procedure ComWaitForClear(ComPort:Byte)                                 *}
  641. {*                                                                          *}
  642. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  643. {*                    Exits immediately if out of range or port unopened.   *}
  644. {*                                                                          *}
  645. {*  A call to ComWaitForClear will stop processing until the selected out-  *}
  646. {*  put buffer is completely emptied.  Typically used just before a call    *}
  647. {*  to the CloseCom procedure to prevent premature cut-off of messages in   *}
  648. {*  transit.                                                                *}
  649. {*                                                                          *}
  650. {****************************************************************************}
  651.  
  652. PROCEDURE ComWaitForClear(ComPort : BYTE);
  653. VAR
  654.   Empty : BOOLEAN;
  655. BEGIN
  656.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  657.   REPEAT
  658.     Empty := (C_Status[ComPort] AND $04) = $04;
  659.     Empty := Empty AND ((Port[C_PortAddr[ComPort] + C_IER] AND $02) = $00);
  660.   UNTIL Empty;
  661. END;
  662.  
  663. {****************************************************************************}
  664. {*                                                                          *}
  665. {*  Procedure ComWrite(ComPort:Byte; St:String)                             *}
  666. {*                                                                          *}
  667. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  668. {*                    Exits immediately if out of range or port unopened.   *}
  669. {*  St:String     ->  String to send                                        *}
  670. {*                                                                          *}
  671. {*  Sends string <St> out communications port <ComPort>.                    *}
  672. {*                                                                          *}
  673. {****************************************************************************}
  674.  
  675. PROCEDURE ComWrite(ComPort : BYTE; St : STRING);
  676. VAR
  677.   X : BYTE;
  678. BEGIN
  679.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  680.   FOR X := 1 TO LENGTH(St) DO
  681.     ComWriteChW(ComPort,St[X]);
  682. END;
  683.  
  684. {****************************************************************************}
  685. {*                                                                          *}
  686. {*  Procedure ComWriteln(ComPort:Byte; St:String);                          *}
  687. {*                                                                          *}
  688. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  689. {*                    Exits immediately if out of range or port unopened.   *}
  690. {*  St:String     ->  String to send                                        *}
  691. {*                                                                          *}
  692. {*  Sends string <St> with a CR and LF appended.                            *}
  693. {*                                                                          *}
  694. {****************************************************************************}
  695.  
  696. PROCEDURE ComWriteln(ComPort : BYTE; St : STRING);
  697. VAR
  698.   X : BYTE;
  699. BEGIN
  700.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  701.   FOR X := 1 TO LENGTH(St) DO
  702.     ComWriteChW(ComPort,St[X]);
  703.   ComWriteChW(ComPort,#13);
  704.   ComWriteChW(ComPort,#10);
  705. END;
  706.  
  707. {****************************************************************************}
  708. {*                                                                          *}
  709. {*  Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);         *}
  710. {*                                                                          *}
  711. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  712. {*                    Exits immediately if out of range or port unopened.   *}
  713. {*  St:String     ->  String to send                                        *}
  714. {*  Dly:Word      ->  Time, in milliseconds, to delay between each char.    *}
  715. {*                                                                          *}
  716. {*  ComWriteWithDelay will send string <St> to port <ComPort>, delaying     *}
  717. {*  for <Dly> milliseconds between each character.  Useful for systems that *}
  718. {*  cannot keep up with transmissions sent at full speed.                   *}
  719. {*                                                                          *}
  720. {****************************************************************************}
  721.  
  722. PROCEDURE ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
  723. VAR
  724.   X : BYTE;
  725. BEGIN
  726.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  727.   ComWaitForClear(ComPort);
  728.   FOR X := 1 TO LENGTH(St) DO
  729.     BEGIN
  730.       ComWriteChW(ComPort,St[X]);
  731.       ComWaitForClear(ComPort);
  732.       DELAY(Dly);
  733.     END;
  734. END;
  735.  
  736. {****************************************************************************}
  737. {*                                                                          *}
  738. {* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
  739. {*                                                                          *}
  740. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  741. {*                    Exits immediately if out of range or port unopened.   *}
  742. {*  St:String     <-  Edited string from remote                             *}
  743. {*  Size:Byte;    ->  Maximum allowable length of input                     *}
  744. {*  Echo:Boolean; ->  Set TRUE to echo received characters                  *}
  745. {*                                                                          *}
  746. {*  ComReadln is the remote equivalent of the standard Pascal READLN pro-   *}
  747. {*  cedure with some enhancements.  ComReadln will accept an entry of up to *}
  748. {*  40 printable ASCII characters, supporting ^H and ^X editing commands.   *}
  749. {*  Echo-back of the entry (for full-duplex operation) is optional.  All    *}
  750. {*  control characters, as well as non-ASCII (8th bit set) characters are   *}
  751. {*  stripped.  If <Echo> is enabled, ASCII BEL (^G) characters are sent     *}
  752. {*  when erroneous characters are intercepted.  Upon receipt of a ^M (CR),  *}
  753. {*  the procedure is terminated and the final string result returned.       *}
  754. {*                                                                          *}
  755. {****************************************************************************}
  756.  
  757. PROCEDURE ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
  758. VAR
  759.   Len,X : BYTE;
  760.   Ch : CHAR;
  761.   Done : BOOLEAN;
  762. BEGIN
  763.   St := '';
  764.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  765.   Done := FALSE;
  766.   REPEAT
  767.     Len := LENGTH(St);
  768.     Ch := CHR(ORD(ComReadChW(ComPort)) AND $7F);
  769.     CASE Ch OF
  770.       ^H : IF Len > 0 THEN
  771.              BEGIN
  772.                DEC(Len);
  773.                St[0] := CHR(Len);
  774.                IF Echo THEN ComWrite(ComPort,#8#32#8);
  775.              END
  776.            ELSE
  777.              ComWriteChW(ComPort,^G);
  778.       ^M : BEGIN
  779.              Done := TRUE;
  780.              IF Echo THEN ComWrite(ComPort,#13#10);
  781.            END;
  782.       ^X : BEGIN
  783.              St := '';
  784.              IF Len = 0 THEN ComWriteCh(ComPort,^G);
  785.              IF Echo THEN
  786.                FOR X := 1 TO Len DO
  787.                  ComWrite(ComPort,#8#32#8);
  788.            END;
  789.       #32..#127 : IF Len < Size THEN
  790.                     BEGIN
  791.                       INC(Len);
  792.                       St[Len] := Ch;
  793.                       St[0] := CHR(Len);
  794.                       IF Echo THEN ComWriteChW(ComPort,Ch);
  795.                     END
  796.                   ELSE
  797.                     IF Echo THEN ComWriteChW(ComPort,^G);
  798.     ELSE
  799.       IF Echo THEN ComWriteChW(ComPort,^G)
  800.     END;
  801.   UNTIL Done;
  802. END;
  803.  
  804. {****************************************************************************}
  805. {*                                                                          *}
  806. {*  Function ComExist(ComPort:Byte) : Boolean                               *}
  807. {*                                                                          *}
  808. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  809. {*                    Returns FALSE if out of range                         *}
  810. {*  Returns TRUE if hardware for selected port is detected & tests OK       *}
  811. {*                                                                          *}
  812. {*  Function ComExist performs a high-speed short loopback test on the      *}
  813. {*  selected port to determine if it indeed exists.  Use this function      *}
  814. {*  before attempts to OPEN a port for I/O (although this function is       *}
  815. {*  called by OpenCom to prevent such an occurance).                        *}
  816. {*  NOTE!  Although pains are taken to preserve the 8250 state before the   *}
  817. {*  port test takes place, it is nonetheless recommended that this function *}
  818. {*  NOT be called while a port is actually OPEN.  Doing so may cause the    *}
  819. {*  port to behave erratically.                                             *}
  820. {*                                                                          *}
  821. {****************************************************************************}
  822.  
  823. FUNCTION ComExist(ComPort : BYTE) : BOOLEAN;
  824. CONST
  825.   TestByte1 : BYTE = $0F;
  826.   TestByte2 : BYTE = $F1;
  827. VAR
  828.   P : WORD;
  829.   M,L,B1,B2 : BYTE;
  830. BEGIN
  831.   ComExist := FALSE;
  832.   IF (ComPort < 1) OR (ComPort > C_MaxPort) THEN EXIT;
  833.   P := C_PortAddr[ComPort];
  834.   M := Port[P + C_MCR];                            { Save MCR }
  835.   L := Port[P + C_LCR];                            { Save LCR }
  836.   Port[P + C_MCR] := $10;                          { Enable loopback mode }
  837.   Port[P + C_LCR] := $80;                          { Enable divisor latch mode }
  838.   B1 := Port[P];                                 { Save current baud rate }
  839.   B2 := Port[P + 1];
  840.   Port[P] := 4;                                  { Set baud rate to 28000 }
  841.   Port[P + 1] := 0;
  842.   Port[P + C_LCR] := $03;                          { Transmit mode 28000:8N1 }
  843.   Port[P] := TestByte1;                          { Test byte #1 }
  844.   DELAY(20);                                     { Wait a bit for loopback }
  845.   IF Port[P] <> TestByte1 THEN EXIT;             { Exit w/error if not echoed }
  846.   Port[P] := TestByte2;                          { Test byte #2 }
  847.   DELAY(20);                                     { Wait a bit for loopback }
  848.   IF Port[P] <> TestByte2 THEN EXIT;             { Exit w/error if not echoed }
  849.   ComExist := TRUE;                              { Test passed: Port exists }
  850.   Port[P + C_LCR] := $80;                          { Restore baud rate }
  851.   Port[P] := B1;
  852.   Port[P + 1] := B2;
  853.   Port[P + C_LCR] := L;                            { Restore parameters }
  854.   Port[P + C_MCR] := M;                            { Restore control lines }
  855. END;
  856.  
  857. {****************************************************************************}
  858. {*                                                                          *}
  859. {*  Function ComTrueBaud(Baud:Longint) : Real                               *}
  860. {*                                                                          *}
  861. {*  Baud:Longint  ->  User baud rate to test.                               *}
  862. {*                    Should be between C_MinBaud and C_MaxBaud.            *}
  863. {*  Returns the actual baud rate based on the accuracy of the 8250 divider. *}
  864. {*                                                                          *}
  865. {*  The ASYNC11 communications package allows the programmer to select ANY  *}
  866. {*  baud rate, not just those that are predefined by the BIOS or other      *}
  867. {*  agency.  Since the 8250 uses a divider/counter chain to generate it's   *}
  868. {*  baud clock, many non-standard baud rates can be generated.  However,    *}
  869. {*  the binary counter/divider is not always capable of generating the      *}
  870. {*  EXACT baud rate desired by a user.  This function, when passed a valid  *}
  871. {*  baud rate, will return the ACTUAL baud rate that will be generated.     *}
  872. {*  The baud rate is based on a 8250 input clock rate of 1.73728 MHz.       *}
  873. {*                                                                          *}
  874. {****************************************************************************}
  875.  
  876. FUNCTION ComTrueBaud(Baud : LONGINT) : REAL;
  877. VAR
  878.   X : REAL;
  879.   Y : WORD;
  880. BEGIN
  881.   X := Baud;
  882.   IF X < C_MinBaud THEN X := C_MinBaud;
  883.   IF X > C_MaxBaud THEN X := C_MaxBaud;
  884.   ComTrueBaud := 115200 / ROUND($900 / (X / 50));
  885. END;
  886.  
  887. {****************************************************************************}
  888. {*                                                                          *}
  889. {*  Procedure ComParams(ComPort:Byte; Baud:Longint;                         *}
  890. {*                      WordSize:Byte; Parity:Char; StopBits:Byte);         *}
  891. {*                                                                          *}
  892. {*  ComPort:Byte   ->  Port # to initialize.  Must be (1 - C_MaxCom)        *}
  893. {*                     Procedure aborted if port # invalid or unopened.     *}
  894. {*  Baud:Longint   ->  Desired baud rate.  Should be (C_MinBaud - C_MaxBaud)*}
  895. {*                     C_MinBaud or C_MaxBaud used if out of range.         *}
  896. {*  WordSize:Byte  ->  Word size, in bits.  Must be 5 - 8 bits.             *}
  897. {*                     8-bit word used if out of range.                     *}
  898. {*  Parity:Char    ->  Parity classification.                               *}
  899. {*                     May be N)one, E)ven, O)dd, M)ark or S)pace.          *}
  900. {*                     N)one selected if classification unknown.            *}
  901. {*  StopBits:Byte  ->  # of stop bits to pad character with.  Range (1-2)   *}
  902. {*                     1 stop bit used if out of range.                     *}
  903. {*                                                                          *}
  904. {*  ComParams is used to configure an OPEN'ed port for the desired comm-    *}
  905. {*  unications parameters, namely baud rate, word size, parity form and     *}
  906. {*  # of stop bits.  A call to this procedure will set up the port approp-  *}
  907. {*  riately, as well as assert the DTR, RTS and OUT2 control lines and      *}
  908. {*  clear all buffers.                                                      *}
  909. {*                                                                          *}
  910. {****************************************************************************}
  911.  
  912. PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
  913. CONST
  914.   C_Stopbit1    = $00;                 { Bit masks for parity, stopbits }
  915.   C_Stopbit2    = $04;
  916.   C_NoParity    = $00;
  917.   C_OddParity   = $08;
  918.   C_EvenParity  = $18;
  919.   C_MarkParity  = $28;
  920.   C_SpaceParity = $38;
  921. VAR
  922.   X : REAL;
  923.   Y,P : WORD;
  924.   DivMSB,DivLSB,BaudB : BYTE;
  925.   WS,SB,PTY : BYTE;
  926. BEGIN
  927.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  928.   INLINE($FA);
  929.   P := C_PortAddr[ComPort];
  930.   { Calculate baud rate divisors }
  931.   X := Baud;
  932.   IF X < C_MinBaud THEN X := C_MinBaud;
  933.   IF X > C_MaxBaud THEN X := C_MaxBaud;
  934.   Y := ROUND($900 / (X / 50));
  935.   DivMSB := HI(Y);
  936.   DivLSB := LO(Y);
  937.   { Determine parity mask }
  938.   { Default if unknown: No parity }
  939.   CASE UPCASE(Parity) OF
  940.     'N' : PTY := C_NoParity;
  941.     'E' : PTY := C_EvenParity;
  942.     'O' : PTY := C_OddParity;
  943.     'M' : PTY := C_MarkParity;
  944.     'S' : PTY := C_SpaceParity;
  945.   ELSE
  946.     PTY := C_NoParity;
  947.   END;
  948.   { Determine stop-bit mask }
  949.   { Default if out of range: 1 Stop bit }
  950.   CASE StopBits OF
  951.     1 : SB := C_StopBit1;
  952.     2 : SB := C_StopBit2;
  953.   ELSE
  954.     SB := C_StopBit1;
  955.   END;
  956.   { Determine word-size mask }
  957.   { Default if out of range: 8 bit word size }
  958.   IF (WordSize >= 5) AND (WordSize <= 8) THEN
  959.     WS := WordSize - 5
  960.   ELSE
  961.     WS := 3;
  962.   { Initialize line-control register }
  963.   Y := Port[P] + Port[P + C_LSR];
  964.   Port[P + C_LCR] := WS + SB + PTY;
  965.   { Initialize baud rate divisor latches }
  966.   Port[P + C_LCR] := Port[P + C_LCR] OR $80;
  967.   Port[P] := DivLSB;
  968.   Port[P + 1] := DivMSB;
  969.   Port[P + C_LCR] := Port[P + C_LCR] AND $7F;
  970.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  971.   { Assert RS323 control lines (DTR,RTS,OUT2) & exit }
  972.   Port[P + C_MCR] := $0B;
  973.   ClearCom(ComPort,'B');
  974.   {begin new stuff srl*}
  975.   Port[$20] := $20;
  976.   IF C_CascadeOK THEN
  977.     Port[$A0] := $20;
  978.   {end new stuff srl*}
  979.   INLINE($FB);
  980. END;
  981.  
  982. {****************************************************************************}
  983. {*                                                                          *}
  984. {*  Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
  985. {*                                                                          *}
  986. {*  ComPort:Byte        ->  Port # to OPEN (1 - C_MaxCom)                   *}
  987. {*                          Request will fail if out of range or port OPEN  *}
  988. {*  InBufferSize:Word   ->  Requested size of input (receive) buffer        *}
  989. {*  OutBufferSize:Word  ->  Requested size of output (transmit) buffer      *}
  990. {*  Returns success/fail status of OPEN request (TRUE if OPEN successful)   *}
  991. {*                                                                          *}
  992. {*  OpenCom must be called before any activity (other than existence check, *}
  993. {*  see the ComExist function) takes place.  OpenCom initializes the        *}
  994. {*  interrupt drivers and serial communications hardware for the selected   *}
  995. {*  port, preparing it for I/O.  Memory for buffers is allocated on the     *}
  996. {*  Pascal "heap", thus freeing data-segment memory for larger more data-   *}
  997. {*  intensive programs.  Once a port has been OPENed, a call to ComParams   *}
  998. {*  should be made to set up communications parameters (baud rate, parity   *}
  999. {*  and the like).  Once this is done, I/O can take place on the port.      *}
  1000. {*  OpenCom will return a TRUE value if the opening procedure was success-  *}
  1001. {*  ful, or FALSE if it is not.                                             *}
  1002. {*                                                                          *}
  1003. {****************************************************************************}
  1004.  
  1005. FUNCTION OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
  1006. VAR
  1007.   TempVec : POINTER;
  1008.   P : WORD;
  1009.   IntLn,Cas_IntLn,X : BYTE;
  1010. BEGIN
  1011.   { Ensure that port was not previously open }
  1012.   OpenCom := FALSE;
  1013.   C_CascadeOK := FALSE;
  1014.   C_cascade := 0;
  1015.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR C_PortOpen[ComPort] THEN EXIT;
  1016.   C_msrport := c_portaddr[comport] + c_msr;
  1017.   { Clear any pending activity from 8250 interrupt queue }
  1018.   INLINE($FA);
  1019.   { Set up interrupt vectors & 8259 PIC }
  1020.   P := C_PortAddr[ComPort];
  1021.   oldier := port[P + c_ier];
  1022.   oldmcr := port[P + c_mcr];
  1023.   Port[P + C_IER] := $0D;
  1024.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  1025.   IntLn := C_PortInt[ComPort];
  1026.   IF IntLn > 7 THEN
  1027.      C_CascadeOK := TRUE;
  1028.   IF C_CascadeOK THEN
  1029.     BEGIN
  1030.       Cas_IntLn := IntLn - 8;
  1031.       GETINTVEC($70 + Cas_IntLn,TempVec);
  1032.       IF C_OldINTVec[IntLn] <> TempVec THEN
  1033.         BEGIN
  1034.           C_Cascade := 1;
  1035.           C_OldINTVec[IntLn] := TempVec;
  1036.           SETINTVEC($70 + Cas_IntLn,@Int_Handler);
  1037.           Port[$21] := Port[$21] AND (($01 SHL $02) XOR $FF);
  1038.           X := Port[$21];
  1039.           Port[$A1] := Port[$A1] AND (($01 SHL Cas_IntLn) XOR $FF);
  1040.           X := Port[$A1];
  1041.         END;
  1042.     END
  1043.   ELSE
  1044.     BEGIN
  1045.       GETINTVEC(8 + IntLn,TempVec);
  1046.       IF C_OldINTVec[IntLn] <> TempVec THEN
  1047.         BEGIN
  1048.           C_OldINTVec[IntLn] := TempVec;
  1049.           SETINTVEC(8 + IntLn,@Int_Handler);
  1050.           Port[$21] := Port[$21] AND (($01 SHL IntLn) XOR $FF);
  1051.           X := Port[$21];
  1052.         END;
  1053.     END;
  1054.  
  1055.   { new stuff srl*}
  1056.   Port[P + C_MCR] := $0B;
  1057.   { Allocate memory for I/O buffers }
  1058.   C_InSize[ComPort] := InBufferSize;
  1059.   C_OutSize[ComPort] := OutBufferSize;
  1060.   GETMEM(C_InBufPtr[ComPort],InBufferSize);
  1061.   GETMEM(C_OutBufPtr[ComPort],OutBufferSize);
  1062.   { Set up default parameters for port }
  1063.   C_RTSOn[ComPort] := InBufferSize - 2;
  1064.   C_RTSOff[ComPort] := InBufferSize - 1;
  1065.   C_StartChar[ComPort] := ^Q;
  1066.   C_StopChar[ComPort] := ^S;
  1067.   C_PortOpen[ComPort] := TRUE;
  1068.   OpenCom := TRUE;
  1069.   INLINE($FB);
  1070. END;
  1071.  
  1072. {****************************************************************************}
  1073. {*                                                                          *}
  1074. {*  Procedure CloseCom(ComPort:Byte)                                        *}
  1075. {*                                                                          *}
  1076. {*  ComPort:Byte  ->  Port # to close                                       *}
  1077. {*                    Request ignored if port closed or out of range.       *}
  1078. {*                                                                          *}
  1079. {*  CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
  1080. {*  buffers and drop the DTR and RTS signal lines for a port opened with    *}
  1081. {*  the OpenCom function.  It should be called before exiting your program  *}
  1082. {*  to ensure that the port is properly shut down.                          *}
  1083. {*  NOTE:  CloseCom shuts down a communications channel IMMEDIATELY,        *}
  1084. {*         even if there is data present in the input or output buffers.    *}
  1085. {*         Therefore, you may wish to call the ComWaitForClear procedure    *}
  1086. {*         before closing the ports.                                        *}
  1087. {*                                                                          *}
  1088. {****************************************************************************}
  1089.  
  1090. PROCEDURE CloseCom(ComPort : BYTE);
  1091. VAR
  1092.   ClosePort : BOOLEAN;
  1093.   P,IntLn,Cas_IntLn,X : WORD;
  1094. BEGIN
  1095.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  1096.   { Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
  1097.   INLINE($FA);
  1098.   P := C_PortAddr[ComPort];
  1099.   Port[P + C_IER] := oldier;
  1100.   C_PortOpen[ComPort] := FALSE;
  1101.   { Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
  1102.   IntLn := C_PortInt[ComPort];
  1103.   ClosePort := TRUE;
  1104.   FOR X := 1 TO C_MaxCom DO
  1105.     IF C_PortOpen[X] AND (C_PortInt[X] = IntLn) THEN
  1106.       ClosePort := FALSE;
  1107.   IF ClosePort THEN
  1108.     IF C_CascadeOk THEN
  1109.       BEGIN
  1110.         Cas_IntLn := IntLn - 8;
  1111.         Port[$21] := Port[$21] OR ($01 SHR $02);
  1112.         X := Port[$21];
  1113.         Port[$A1] := Port[$A1] OR ($01 SHR Cas_IntLn);
  1114.         X := Port[$A1];
  1115.         SETINTVEC($70 + Cas_IntLn,C_OldINTVec[IntLn]);
  1116.       END
  1117.     ELSE
  1118.       BEGIN
  1119.         Port[$21] := Port[$21] OR ($01 SHR IntLn);
  1120.         X := Port[$21];
  1121.         SETINTVEC(8 + IntLn,C_OldINTVec[IntLn]);
  1122.       END;
  1123.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  1124.   { Deallocate buffers }
  1125.   FREEMEM(C_InBufPtr[ComPort],C_InSize[ComPort]);
  1126.   FREEMEM(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
  1127.   INLINE($FB);
  1128. END;
  1129.  
  1130. {****************************************************************************}
  1131. {*                                                                          *}
  1132. {*  Procedure CloseAllComs                                                  *}
  1133. {*                                                                          *}
  1134. {*  CloseAllComs will CLOSE all currently OPENed ports.  See the CloseCom   *}
  1135. {*  procedure description for more details.                                 *}
  1136. {*                                                                          *}
  1137. {****************************************************************************}
  1138.  
  1139. PROCEDURE CloseAllComs;
  1140. VAR
  1141.   X : BYTE;
  1142. BEGIN
  1143.   FOR X := 1 TO C_MaxCom DO
  1144.     IF C_PortOpen[X] THEN
  1145.       CloseCom(X);
  1146. END;
  1147.  
  1148. {****************************************************************************}
  1149. {*                                                                          *}
  1150. {*                        UNIT Initialization Code                          *}
  1151. {*                                                                          *}
  1152. {****************************************************************************}
  1153.  
  1154. BEGIN
  1155.   FOR x := 1 TO C_MaxPort DO
  1156.     BEGIN
  1157.       C_PortOpen[x] := FALSE;
  1158.       C_InBufPtr[x] := NIL;
  1159.       C_OutBufPtr[x] := NIL;
  1160.       C_OldIntVec[x] := NIL;
  1161.       C_InHead[x] := 0;
  1162.       C_OutHead[x] := 0;
  1163.       C_InTail[x] := 0;
  1164.       C_OutTail[x] := 0;
  1165.       C_InSize[x] := 0;
  1166.       C_OutSize[x] := 0;
  1167.       C_RTSOn[x] := $FFFF;
  1168.       C_RTSOff[x] := $FFFF;
  1169.       C_StartChar[x] := ^Q;
  1170.       C_StopChar[x] := ^S;
  1171.       C_Status[x] := $05;
  1172.       C_Ctrl[x] := 0;
  1173.       C_XL3Ptr[x] := 0;
  1174.       C_buffull[x] := 0;
  1175.       C_cascade := 0;
  1176.     END;
  1177. END.
  1178.